home *** CD-ROM | disk | FTP | other *** search
/ Turnbull China Bikeride / Turnbull China Bikeride - Disc 1.iso / ARGONET / PD / MODULES / CSDVAR.ZIP / CSDVar.s (.txt) < prev    next >
RISC OS BBC BASIC V Source  |  1997-10-25  |  59KB  |  1,630 lines

  1.  >CSDVar/s
  2. $+" / "+
  3.  "BasAsmLib"
  4. init_os_dict_tokenise
  5. SHOWREGS_USED = 0
  6. Obufsize%=512      : 
  7.  buffer size for reading CSD name (+128 for workspace)
  8.     Eelipsis$=" 
  9.  "    : 
  10.  default string to use when clipping strings
  11. 7elipsis_len%=40   : 
  12.  default elipsis cut off point
  13. Bhtos%=0:htcs%=0   : 
  14.  used to see how much FNosd has saved us!
  15. Gscratch_offset%   = 128 : 
  16.  scratch workspace into module workspace
  17. Dcsdvarlen_offset% = 0   : 
  18.  max length of CSD$Var into workspace
  19. Kdirstack_head%    = 4   : 
  20.  offset of ->head of directory stack (queue)
  21. Kdirstack_tail%    = 8   : 
  22.  offset of ->tail of directory stack (queue)
  23. Delipsis_offset%   = 12  : 
  24.  offset of elipsis string for CSD$Var
  25. =max_elipsis_len%  = (scratch_offset%-elipsis_offset%) - 2
  26. Fstackentry_size%  = 12  : 
  27.  size of a stack entry descriptor block
  28. Gstackentry_name%  = 0   : 
  29.  offset of name pointer in a stack entry
  30. 8stackentry_next%  = 4   : 
  31.  offset of 'next' pointer
  32. 8stackentry_prev%  = 8   : 
  33.  offset of 'prev' pointer
  34. swichunk%=&cd000+64*3
  35. VFlag%=1<<28
  36.  code% &4000
  37.  pass%=4 
  38. "Assembling, Pass ";(pass% 
  39.  2 + 1;" ... ";
  40. P%=0:O%=code%
  41. [OPT pass%
  42. .moduleheader
  43. &C.startcode       EQUD 0          \ We are a service module only
  44. '$.initcode        EQUD initialise
  45. (".finalisecode    EQUD finalise
  46. .servicehandler  EQUD 0
  47. *%.titleofset      EQUD titlestring
  48. +$.helpofset       EQUD helpstring
  49. ,#.tableofset      EQUD commtable
  50. -#.swichunk        EQUD swichunk%
  51. .$.swihandlerofset EQUD swihandler
  52. /(.swidectabofset  EQUD swidecodetable
  53. .swidecodeofset  EQUD 0
  54. .titlestring
  55. EQUS "CSDVar":equb 0
  56. .helpstring
  57. 5;EQUS "CSDVar":EQUB 9:equb 9:EQUS "2.13 ("+
  58. $,5,11)+")"
  59. 6 equs " 
  60.  Musus Umbra":equb 0
  61. .swidecodetable
  62. 9+EQUS "CSDVar":dcb 0        \ SWI prefix
  63. :=equs "Read":dcb 0          \ Read the CSD's full pathname
  64. ;<equs "MaxLen":dcb 0        \ Set max length of <CSD$Var>
  65. <.equs "Clip":dcb 0          \ clip a string
  66. =2equs "StackInfo":dcb 0     \ Get info on stack
  67. >7equs "StackControl":dcb 0  \ Misc. stack operations
  68. ?@equs "PushDir":dcb 0       \ push a directory onto the stack
  69. @?equs "PopDir":dcb 0        \ pop a directory from the stack
  70. ABequs "UnstackDir":dcb 0    \ remove a directory from the stack
  71. B<equs "UnstackAll":dcb 0    \ deallocate the entire stack
  72. C4equs "Canonicalise":dcb 0  \ canonicalise a path
  73. DRequs "FreeBlock":dcb 0     \ free a block claimed with OS_Module 6 (eg. above)
  74. EQequs "AddToPath":dcb 0     \ intelligently add a directory to a path variable
  75. F<equs "ExistsInPath":dcb 0  \ does a dir exist in a path?
  76. G1equs "GSTrans":dcb 0       \ GSTrans a string
  77. H equs "MakeArgV":dcb 0      \
  78. equs "FreeArgV":dcb 0
  79. JCequs "Debug1":dcb 0        \ print R0 in hex with a preceding &
  80. EQUB 0:ALIGN
  81. M5.swihandler    \ code taken straigt from the PRM!
  82. N.CMP      R11,#(EndOfJumpTable-JumpTable)/4
  83. ADDLO    PC,PC,R11,LSL#2
  84. B        unknownswierror
  85. .JumpTable
  86. B read_pwd_swi
  87. B set_max_len_swi
  88. B clip_length_swi
  89. B dir_stack_info_swi
  90. B dir_stack_ctrl_swi
  91. B pushdir_swi
  92. B popdir_swi
  93. B unstack_dir_swi
  94. B unstack_all_swi
  95. B canonicalise
  96. B freeblock
  97. B add_to_path_swi
  98. B exists_in_path
  99. B gs_trans
  100. B swi_make_argv
  101. B swi_free_argv
  102. B print_address
  103. .EndOfJumpTable
  104. .unknownswierror
  105. ADR      R0,errtoken
  106. MOV      R1,#0
  107. MOV      R2,#0
  108. adr    (4,titlestring)
  109. j2STMFD    R13!,{R14}           \ DAMN THAT PRM!
  110. k(SWI      "XMessageTrans_ErrorLookup"
  111. l8LDMFD    R13!,{R14}           \ Bugger Bugger Bugger
  112. RS     PC,R14,#VFlag%
  113. .errtoken
  114. o'EQUD &1E6:EQUS "BadSWI":EQUB0:ALIGN
  115. .initialise
  116. STMFD   R13!,{R7-R11,R14}
  117. s/LDR     R2,[R12]        \ get !private word
  118. t0CMP     R2,#0           \ is this a re-init?
  119. bne     reinit
  120. v:MOV     R0,#6           \ OS_Module6 = Claim workspace
  121. w;MOV     R3,#bufsize%    \ We want 512 bytes (overkill!)
  122. x(SWI     "XOS_Module"    \ do the swi
  123. ldmvsfd  r13!,{r7-r11,pc}
  124. zESTR     R2,[R12]        \ store workspace pointer in private word
  125. mov     r0,#elipsis_len%
  126. |&str     r0,[r2,#csdvarlen_offset%]
  127. }#add     r12,r2,#elipsis_offset%
  128. adr   (0,defelips)
  129. .cpy_def_el
  130. ldrb    r1,[r0],#1
  131. strb    r1,[r12],#1
  132. cmp     r1,#31
  133. bgt     cpy_def_el
  134. mov     r11,#0
  135. $str     r11,[r2,#dirstack_head%]
  136. $str     r11,[r2,#dirstack_tail%]
  137. ldrb    r1,[r10]
  138. 2cmp     r1,#32    \ did we have any arguments?
  139. (mov     r12,r2    \ module workspace
  140. mov     r1,r10
  141.  blgt    setvariablevalue_ini
  142. ldmvsfd  r13!,{r7-r11,pc}
  143. .reinit
  144. bl      setvariable
  145. ldmfd    r13!,{r7-r11,pc}
  146. .gs_trans
  147. \ On entry:
  148. $\        r0 -> string to GStrans
  149. \ On exit:
  150. F\        r0 = OS_Module 6 claimed buffer conating GSTrans'd string
  151. \        (or error)
  152. stmfd    r13!,{r1-r5,r14}
  153. mov      r4,r0
  154. mov      r0,#6
  155. >mov      r3,#64            \ start by trying for <64 bytes
  156. &swi      "XOS_Module"      \ claim
  157. ,mov      r5,r2             \ r5 = buffer
  158. ldmvsfd  r13!,{r1-r5,pc}
  159. .gs_trans_loop
  160. 2mov      r0,r4             \ string to GStrans
  161. 'mov      r1,r5             \ buffer
  162. ,mov      r2,r3             \ buffer size
  163. swi      "XOS_GSTrans"
  164. bvs      gstrans_error
  165. movcc    r0,r1
  166. 3ldmccfd  r13!,{r1-r5,pc}^  \ exit if successful
  167. mov      r0,#13
  168. mov      r2,r5
  169. mov      r5,r3
  170. 6mov      r3,#32            \ try for 32 bytes more
  171. -swi      "XOS_Module"      \ extend block
  172. Kadd      r3,r5,r3          \ add the extension size onto the block size
  173. 3movvc    r5,r2             \ r5 = -> new buffer
  174. bvc      gs_trans_loop
  175. .gstrans_error
  176. mov      r1,r0
  177. mov      r0,#7
  178. mov      r2,r5
  179. ,swi      "XOS_Module"      \ free buffer
  180. blvs     ie_nf
  181. mov      r0,r1
  182. ldmfd    r13!,{r1-r5,r14}
  183. orrs     pc,r14,#1<<28
  184. .exists_in_path
  185. \ On entry:
  186. /\        r0 -> path variable, as <foo$path>
  187. @\        r1 -> directory name (with or without trailing '.')
  188. \ On exit:
  189. ,\        r3 = 0=>not present, 1=>present
  190. #\        (if error, r1 corrupt)
  191. stmfd    r13!,{r1-r5,r14}
  192. 2mov      r10,r0            \ preserve original
  193. 2mov      r11,r1            \ preserve original
  194. :bl       gs_trans          \ GSTrans the path variable
  195. +ldmvsfd  r13!,{r1-r5,pc}   \ trap error
  196. debpp  ("Path var GSTrans'd to -",0)
  197. 9mov      r1,r0             \ r1 ->GSTrans'd path name
  198. 5mov      r0,r11            \ r0 -> directory name
  199. +bl       gs_trans          \ GSTrans it
  200.  bvc      check_exists_1    \
  201. bl       ie_nf
  202. mov      r10,r0
  203. mov      r0,r1
  204. bl       freeblock
  205. blvs     ie_nf
  206. mov      r0,r10
  207. ldmfd    r13!,{r1-r5,r14}
  208. orrs     pc,r14,#1<<28
  209. .check_exists_1
  210. \ At this point,
  211. +\        r0 -> GSTrans'd directory name
  212. *\        r1 -> GSTrans'd path variable
  213. %\        r10,r11 = original r0,r1
  214. debpp  ("Dir name GSTrans'd to -",0)
  215. mov      r11,r0
  216. stmfd    r13!,{r0,r1}
  217. sub      r1,r1,#1
  218. .chex_loop_1
  219. debpp  ("Hunting for non-space, non-comma in -",1)
  220. mov      r0,r11
  221. .chex_hunt_non_space
  222. .ldrb     r3,[r1,#1]!       \ get next char
  223. cmp      r3,#
  224. 5cmpne    r3,#32            \ terminator or space?
  225.  beq      chex_hunt_non_space
  226. blt      chex_done
  227. mov      r2,r1
  228. debpp  ("Hunting for space, terminator or comma) in -",1)
  229. .chex_hunt_space
  230. ldrb     r3,[r2,#1]!
  231. cmp      r3,#
  232. cmpne    r3,#32
  233. bgt      chex_hunt_space
  234. .chex_found_term
  235. cmp      r3,#32
  236. 9movge    r3,#0             \ term with 0 if not final
  237. 2movlt    r3,#13            \ else term with 13
  238. /strb     r3,[r2]           \ terminate here
  239. \ Okay, so at this point:
  240. %\        r0 -> GSTrans'd dir name
  241. 2\        r1 -> null terminated element of path
  242. &bl       lowcmp            \ same?
  243. :mov      r1,r2             \ start at end of this word
  244. cmp      r0,#0
  245. 'beq      chex_done         \ yipee!
  246. /cmp      r3,#13            \ out of string?
  247. bne      chex_loop_1
  248. .chex_done
  249. debug  ("Chex done-")
  250. C\ At this point, buffer ptrs are on stack, r0==0 => match found
  251. cmp      r0,#0
  252. movne    r12,#0
  253. moveq    r12,#1
  254. ldmfd    r13!,{r0,r1}
  255. bl       freeblock
  256. blvs     ie_nf
  257. mov      r0,r1
  258. bl       freeblock
  259. blvs     ie_nf
  260. ldmfd    r13!,{r1-r5,r14}
  261. mov      r0,r10
  262. mov      r3,r12
  263. debug  ("Exit chex-")
  264. movs     pc,r14
  265. .add_to_path_swi
  266. \ On entry:
  267. =\        r0 -> name of path var as foo, foo$path, or foo:
  268. +\        r1 -> name of directory to add
  269. ,\        r2 = 1 (prepend), or 0 (append)
  270. \ On exit:
  271. \        r0 corrupt
  272. stmfd    r13!,{r1-r5,r14}
  273. stmfd    r13!,{r2}
  274. mov      r10,r0
  275.  7ldr      r12,[r12]                  \ get workspace
  276. !<add      r12,r12,#scratch_offset%   \ r12->scratch space
  277. mov      r5,r12
  278. mov      r11,#
  279. strb     r11,[r12]
  280. .atp_cpy_pth
  281. ldrb     r11,[r0],#1
  282. strb     r11,[r12,#1]!
  283. cmp      r11,#
  284. cmpne    r11,#
  285. cmpne    r11,#
  286. bgt      atp_cpy_pth
  287. mov      r11,#
  288. adr    (11,stringpath)   \ ->"$path>\0"
  289. .atp_cpy_trm
  290. ldrb     r3,[r11],#1
  291. strb     r3,[r12],#1
  292. cmp      r3,#0
  293. bne      atp_cpy_trm
  294. mov      r0,r5
  295. mov      r12,r5
  296. 5$swi      
  297. my_swi("ExistsInPath")
  298. ldmfd    r13!,{r2}
  299. ldmvsfd  r13!,{r1-r5,pc}
  300. 8(cmp      r3,#1             \ exists?
  301. 9,moveq    r0,r10            \ preserve r0
  302. ldmeqfd  r13!,{r1-r5,pc}^
  303. \ At this point:
  304. =1\        r0,5,12 -> "<foo$path>" in workspace
  305. >%\        r1 -> name of dir to add
  306. ?#\        r2 =  pre/app end flag
  307. \        r10 = original r0
  308. A9mov      r0,r1             \ r0 -> name of dir to add
  309. B+bl       gs_trans          \ GSTrans it
  310. CBbl       ispath            \ check for trailing '.' and colons
  311. D4bl       freeblock         \ and free the buffer
  312. mov      r11,r12
  313. mov      r5,r2
  314. G/mov      r0,r12            \ r0-><foo$path>
  315. H8bl       gs_trans          \ gs trans the <foo$path>
  316. I<mov      r2,r0             \ r2 -> gs_trans'd <foo$path>
  317. J9mov      r0,r1             \ r0 -> name of dir to add
  318. bl       strlen
  319. L3add      r3,r0,#3          \ +3 for ",." and \0
  320. MDcmp      r4,#0             \ does the addition need a '.' added?
  321. NMsubne    r3,r3,#1          \ if not, then we don't need the space for it!
  322. mov      r0,#13
  323. swi      "XOS_Module"
  324. bvc      atp_gowi
  325. mov      r10,r0
  326. mov      r0,#7
  327. swi      "XOS_Module"
  328. blvs     ie_nf
  329. mov      r0,r10
  330. ldmfd    r13!,{r1-r5,r14}
  331. orrs     pc,r14,#1<<28
  332. .atp_gowi
  333. \ At this point:
  334. [-\        r12 -> "<foo$path>" in workspace
  335. \%\        r1 -> name of dir to add
  336. ]8\        r2 = buffer containing GSTrans'd <foo$path>
  337. ^3\        r3 = length of $r1 + 3 (or +2 if r4=0)
  338. _"\        r4 = needs a '.' flag
  339. `#\        r5 =  pre/app end flag
  340. \        r10 = original r0
  341. cmp      r5,#0    \ append?
  342. beq      atp_append
  343. .atp_prepend
  344. \ At this point:
  345. g-\        r12 -> "<foo$path>" in workspace
  346. h%\        r1 -> name of dir to add
  347. i8\        r2 = buffer containing GSTrans'd <foo$path>
  348. j3\        r3 = length of $r1 + 3 (or +2 of r4=0)
  349. k"\        r4 = needs a '.' flag
  350. \        r10 = original r0
  351. m6mov      r5,r4             \ r5 = 'add a dot' flag
  352. mov      r0,r2
  353. oDbl       strlen            \ r0 = length of GSTrans'd <foo$path>
  354. cmp      r0,#0
  355. qGbeq      atp_append        \ prepend => append if <foo$path> is ""!
  356. r>add      r11,r0,r2         \ r11 -> terminator of -- "" --
  357. s=add      r4,r11,r3         \ r4 -> byte to relocate to +1
  358. .atp_pre_loop
  359. u)ldrb     r0,[r11],#-1      \ get byte
  360. v strb     r0,[r4,#-1]!      \
  361. w*cmp      r11,r2            \ done yet?
  362. bge      atp_pre_loop
  363. mov      r4,r2
  364. .atp_pre_cpy_dir
  365. ldrb     r0,[r1],#1
  366. strb     r0,[r4],#1
  367. cmp      r0,#32
  368. bgt      atp_pre_cpy_dir
  369. mov      r0,#
  370. cmp      r5,#1
  371. streqb   r0,[r4,#-1]
  372. subne    r4,r4,#1
  373. mov      r0,#
  374. strb     r0,[r4]
  375. b        atp_setvar
  376. .atp_append
  377. \ At this point:
  378. -\        r12 -> "<foo$path>" in workspace
  379. %\        r1 -> name of dir to add
  380. 8\        r2 = buffer containing GSTrans'd <foo$path>
  381. 3\        r3 = length of $r1 + 3 (or +2 of r4=0)
  382. "\        r4 = needs a '.' flag
  383. \        r10 = original r0
  384. 6mov      r5,r4             \ r5 = 'add a dot' flag
  385. mov      r0,r2
  386. bl       strlen
  387. Aadd      r4,r2,r0          \ r4 -> byte to start appending at
  388. cmp      r0,#0
  389. Kmov      r0,#
  390. ","        \ was movne  - ie. new path rather than append
  391. Dstrb     r0,[r4],#1        \ was strneb - to an empty path.  Um.
  392. .atp_app_cpy_dir
  393. ldrb     r0,[r1],#1
  394. strb     r0,[r4],#1
  395. cmp      r0,#32
  396. bgt      atp_app_cpy_dir
  397. mov      r0,#
  398. cmp      r5,#1
  399. streqb   r0,[r4,#-1]
  400. subne    r4,r4,#1
  401. mov      r0,#0
  402. strb     r0,[r4]
  403. .atp_setvar
  404. \ At this point:
  405. -\        r12 -> "<foo$path>" in workspace
  406. 9\        r2 = buffer containing new value of variable
  407. \        r10 = original r0
  408. mov      r5,r2
  409. mov      r0,r2
  410. bl       strlen
  411. mov      r2,r0
  412. 6add      r12,r12,#1        \ skip '<' in workspace
  413. mov      r11,r12
  414. .find_close_angle
  415. ldrb     r3,[r11],#1
  416. cmp      r3,#
  417. bne      find_close_angle
  418. mov      r3,#0
  419. 4strb     r3,[r11,#-1]      \ replace '>' with \0
  420. mov      r0,r12
  421. mov      r1,r5
  422. mov      r3,#0
  423. +bl       getvartype        \ sets up R4
  424. \mov      r4,#4
  425. swi      "XOS_SetVarVal"
  426. movvc    r0,#0
  427. mov      r11,r0
  428. mov      r0,r5
  429. bl       freeblock
  430. blvs     ie_nf
  431. mov      r0,r11
  432. ldmfd    r13!,{r1-r5,r14}
  433. cmp      r0,#0
  434. moveq    r0,r10
  435. orrne    r14,r14,#1<<28
  436. movs     pc,r14
  437. .ispath
  438. \ On entry, r1->name
  439. L\ On exit, r4 is path flag; 1=>needs a '.' appending, 0=>is a path as is
  440. stmfd    r13!,{r0-r1,r14}
  441. mov      r0,r1
  442. bl       strlen
  443. 1add      r0,r0,r1          \ r0 -> terminator
  444. mov      r4,#1
  445. .ip_sbl
  446. .ldrb     r1,[r0,#-1]!      \ get prev char
  447. #cmp      r1,#
  448. "."        \ dot?
  449. %cmpne    r1,#
  450. ":"        \ colon?
  451. moveq    r4,#0
  452. 2cmp      r1,#32            \ found a char yet?
  453. beq      ip_sbl
  454. %ldmfd    r13!,{r0-r1,pc}^  \ bye!
  455. .getvartype
  456. \ On entry, r0->var name
  457. \ On exit, r4 = var type
  458. stmfd    r13!,{r0-r3,r14}
  459. mov      r1,#0
  460. mov      r2,#1<<31
  461. mov      r3,#0
  462. mov      r4,#0
  463. swi      "XOS_ReadVarVal"
  464. %cmp      r2,#0    \ non existent?
  465. .moveq    r4,#0    \ treat as simple string
  466. ldmfd    r13!,{r0-r3,pc}^
  467. .dir_stack_info_swi
  468. \ On entry -
  469. \ On exit:
  470. E\        r0 = address of 'head' (top) entry (or NULL if no stack)
  471. H\        r1 = address of 'tail' (bottom) entry (of NULL if no stack)
  472. \        r2 = stack entries
  473. %\        r3 = bytes used by stack
  474. ?ldr      r12,[r12]                  \ get workspace pointer
  475. stmfd    r13!,{r4,r14}
  476. 9ldr      r4,[r12,#dirstack_head%]   \ pointer to head
  477. 9ldr      r1,[r12,#dirstack_tail%]   \ pointer to tail
  478. 6mov      r2,#0                      \ init counter
  479. 9mov      r3,#0                      \ init bytes used
  480. $cmp      r4,#0    \ stack empty?
  481. beq      dsis_done
  482. .dsis_loop
  483. Dadd      r3,r3,#stackentry_size%    \ size += sizeof(stackentry)
  484. 4add      r2,r2,#1                   \ counter ++
  485. &ldr      r0,[r4,#stackentry_name%]
  486. bl       strlen
  487. Fadd      r0,r0,#1                   \ include the NULL terminator!
  488. Fadd      r3,r3,r0                   \ size += strlen(scan->name)+1
  489. =ldr      r4,[r4,#stackentry_prev%]  \ scan = scan -> prev
  490. Bcmp      r4,#0                      \ scan = 0 (ie. finished)?
  491. 8bne      dsis_loop                  \ until scan = 0
  492. .dsis_done
  493. 9ldr      r0,[r12,#dirstack_head%]   \ pointer to head
  494. /ldmfd    r13!,{r4,pc}^              \ byee!
  495. .strlen
  496. \ On entry, r0 -> string
  497. $\ On exit, r0 = length of string
  498. stmfd    r13!,{r1,r2}
  499. sub      r1,r0,#1
  500. .strlen_1
  501. ldrb     r2,[r1,#1]!
  502. cmp      r2,#32
  503. bge      strlen_1
  504. sub      r0,r1,r0
  505. ldmfd    r13!,{r1,r2}
  506. movs     pc,r14
  507. .is_in_RMA
  508. \ Internal use
  509. \ On entry:
  510. \        r0 = address
  511. \ On exit:
  512. H\        r0 preserved if address is in RMA, errptr & V set otherwise
  513. stmfd    r13!,{r1-r3,r14}
  514. 1mov      r3,r0             \ copy the address
  515. $mov      r0,#1             \ RMA
  516. "swi      "XOS_ReadDynamicArea"
  517. =cmp      r0,r3             \ is address >= start of area?
  518. &blt      not_in_RMA        \ oops!
  519. 4add      r0,r0,r1          \ end address of area
  520. ;cmp      r0,r3             \ is address <= end of area?
  521. &blt      not_in_RMA        \ oops!
  522. mov      r0,r3
  523. ldmfd    r13!,{r1-r3,pc}^
  524. .not_in_RMA
  525. adr    (0,nirma_eblk)
  526. ldmfd    r13!,{r1-r3,r14}
  527. orrs     pc,r14,#1<<28
  528. .dir_stack_ctrl_swi
  529. \ On entry:
  530. &D\        r0 = address of new 'head' (top) [must be in RMA], or 0
  531. 'G\        r1 = address of new 'tail' (bottom) [must be in RMA], or 0
  532. \ On exit:
  533. \        All regs preserved
  534. stmfd    r13!,{r2,r14}
  535. +6ldr      r12,[r12]         \ get workspace pointer
  536. ,.cmp      r0,#0             \ is new head 0
  537. -1cmpne    r1,#0             \ or is the tail 0
  538. .(moveq    r2,r0             \ (dufge)
  539. /?beq      store_new_ends    \ skip 'in RMA' check and update
  540. 0Fbl       is_in_RMA         \ test to see if it's in the RMA or not
  541. 19ldmvsfd  r13!,{r2,pc}      \ return error if it isn't
  542. mov      r2,r0
  543. mov      r0,r1
  544. 4Fbl       is_in_RMA         \ test to see if it's in the RMA or not
  545. 59ldmvsfd  r13!,{r2,pc}      \ return error if it isn't
  546. .store_new_ends
  547. 7%str      r0,[r12,#dirstack_tail%]
  548. 8%str      r2,[r12,#dirstack_head%]
  549. ldmfd    r13!,{r2,pc}^
  550. .pushdir_swi
  551. \ On entry:
  552. =<\        r0 -> directory name to push (or 0 to push CSD)
  553. \ On exit:
  554. ?/\        r0 preserved or error ptr if V set
  555. ldr      r12,[r12]
  556. stmfd    r13!,{r1-r5,r14}
  557. B5mov      r5,r0             \ preserve original r0
  558. C%cmp      r0,#0             \ CSD?
  559. adrc   ("eq",0,pathname) \ ->"@"
  560. EJbl       canonicalise      \ canonicalise the path (new address in r0)
  561. F-ldmvsfd  r13!,{r1-r5,pc}   \ catch errors
  562. G>mov      r4,r0             \ preserve -> canonicalise name
  563. H&mov      r0,#6             \ claim
  564. IJmov      r3,#stackentry_size%       \ size of a stack entry descriptor
  565. J0swi      "XOS_Module"      \ claim workspace
  566. K6bvc      pushdir_swi_1     \ if succeded, carry on
  567. L7mov      r5,r0             \ preserve error pointer
  568. M5mov      r0,r4             \ -> canonicalise name
  569. N-bl       freeblock         \ free storage
  570. blvs     ie_nf
  571. P6mov      r0,r5             \ restore error pointer
  572. Q.ldmfd    r13!,{r1-r5,r14}  \ and registers
  573. R4orrs     pc,r14,#1<<28     \ and exit with error
  574. SO.pushdir_swi_1             \ r2->stack entry, r4->canon name, r5->orig name
  575. T:ldr      r0,[r12,#dirstack_head%]   \ get top of stack
  576. UGstr      r4,[r2,#stackentry_name%]  \ newnode->name = canon'd name;
  577. mov      r4,#0
  578. W?str      r4,[r2,#stackentry_next%]  \ newnode->next = NULL;
  579. X?str      r0,[r2,#stackentry_prev%]  \ newnode->prev = head;
  580. Y5cmp      r0,#0                      \ if ( head )
  581. ZBstrne    r2,[r0,#stackentry_next%]  \    head->next = newnode;
  582. [:mov      r0,r2                      \  head = newnode;
  583. \Imoveq    r1,r2                      \      if (!head) tail = newnode;
  584. ]Istr      r0,[r12,#dirstack_head%]   \ store new head (always altered)
  585. ^Astreq    r1,[r12,#dirstack_tail%]   \ store tail (if altered)
  586. _2ldmfd    r13!,{r1-r5,pc}^           \ and exit
  587. .popdir_swi
  588. \ On entry -
  589. d@\ On exit  - (r0 possibly an error ptr, else ->new CSD name)
  590. e;ldr      r12,[r12]                  \ get workspace ptr
  591. f4stmfd    r13!,{r1-r3,r14}           \ stack regs
  592. g6ldr      r2,[r12,#dirstack_head%]   \ get head ptr
  593. h0cmp      r2,#0                      \ zero ?
  594. i@ldmeqfd  r13!,{r1-r3,pc}^           \ no stack! exit quietly
  595. j8ldr      r1,[r2,#stackentry_name%]  \ get ->dir name
  596. k1mov      r0,#0                      \ set CSD
  597. l/swi      "XOS_FSControl"            \ do it
  598. m5movvc    r0,#0                      \ if no error
  599. stmfd    r13!,{r0}
  600. oAldr      r3,[r2,#stackentry_prev%]    \ get -> previous entry
  601. p6mov      r0,r2                      \ -> head node
  602. q4bl       freeblock                  \ deallocate
  603. blvs     ie_nf
  604. s8mov      r0,r1                      \ -> name buffer
  605. t4bl       freeblock                  \ deallocate
  606. blvs     ie_nf
  607. v8str      r3,[r12,#dirstack_head%]   \ store new head
  608. w,cmp      r3,#0                      \ 0?
  609. x8streq    r3,[r12,#dirstack_tail%]   \ store new head
  610. yEldmfd    r13!,{r0}                  \ get that (maybe) error back
  611. z:cmp      r0,#0                      \ was it an error?
  612. {2swieq    
  613. my_swi("Read")           \ fudge Ho!
  614. |)ldmfd    r13!,{r1-r3,r14}           \
  615. moveq    pc,r14
  616. ~0orrs     pc,r14,#1<<28              \ splat!
  617. .canonicalise
  618. (\ On entry, r0 -> pathname of object
  619. H\ On exit, r0 -> canonicalised path (block claimed with OS_Module 6)
  620. $\    (or error pointer if V set)
  621. stmfd    r13!,{r1-r5,r14}
  622. #mov      r1,r0     \ ->pathname
  623. *mov      r0,#37    \ Canocicalise path
  624. !mov      r2,#0     \ ->buffer
  625. Kmov      r3,#0     \ I think I'm gonna cry.  Next time I check the PRMs
  626. Lmov      r4,#0     \ *before* !StrongHlp (which didn't mention this bit)
  627. $mov      r5,#0     \ buffer size
  628. swi      "XOS_FSControl"
  629. bvc      canonicalise_1
  630. ldmfd    r13!,{r1-r5,r14}
  631. /orrs     pc,r14,#1<<28    \ exit with error
  632. .canonicalise_1
  633. >rsb      r3,r5,#1  \ r3 = 1-r5, ie. number of bytes needed
  634. mov      r0,#6
  635. swi      "XOS_Module"
  636. bvc      canonicalise_2
  637. ldmfd    r13!,{r1-r5,r14}
  638. /orrs     pc,r14,#1<<28    \ exit with error
  639. .canonicalise_2
  640. mov      r0,#37
  641. mov      r5,r3
  642. Kmov      r3,#0     \ I think I'm gonna cry.  Next time I check the PRMs
  643. Lmov      r4,#0     \ *before* !StrongHlp (which didn't mention this bit)
  644. swi      "XOS_FSControl"
  645. mov      r0,r2
  646. ldmfd    r13!,{r1-r5,pc}^
  647. .freeblock
  648. =\ On entry, r0->block previously returned by canonicalise
  649. 2\ On exit, r0 corrupt or error pointer (V set)
  650. stmfd    r13!,{r2,r14}
  651. mov      r2,r0
  652. mov      r0,#7
  653. swi      "XOS_Module"
  654. ldmfd    r13!,{r2,pc}
  655. .unstack_all_swi
  656. \ On entry:
  657. \        -
  658. \ On exit:
  659. )\        - (r0 possibly error, V set)
  660. stmfd    r13!,{r1-r4,r14}
  661. mov      r10,r0
  662. Iswi      
  663. my_swi("StackInfo")      \ get head, tail, entries and size
  664. ldmvsfd  r13!,{r1-r4,pc}
  665. 0cmp      r2,#0             \ is stack empty?
  666. moveq    r0,r10
  667. 6ldmeqfd  r13!,{r1-r4,pc}^  \ if so, nothing to do!
  668. ,mov      r1,r0             \ r1 = ->head
  669. .ua_free_loop
  670. subs     r2,r2,#1
  671. 4bmi      adnyerr2          \ Ooops... 4am error!
  672. 4ldr      r0,[r1,#stackentry_name%]  \ scan->name
  673. bl       freeblock
  674. blvs     ie_nf
  675. mov      r0,r1
  676. &ldr      r1,[r1,#stackentry_prev%]
  677. bl       freeblock
  678. blvs     ie_nf
  679. 3cmp      r1,#0                      \ done yet?
  680. bne      ua_free_loop
  681. 3mov      r0,r1                      \ r0,r1 = 0
  682. $swi      
  683. my_swi("StackControl")
  684. movvc    r0,r10
  685. ldmfd    r13!,{r1-r4,pc}
  686. .adnyerr2
  687. ldmfd    r13!,{r1-r4,r14}
  688. adr    (0,stack_what_stack)
  689. orrs     pc,r14,#1<<28
  690. .unstack_dir_swi
  691. \ On entry:
  692. =\        r0 -> dir name to unstack (or 0 => top of stack)
  693. \ On exit:
  694. -\        r0 preserved (or error if V set)
  695. stmfd    r13!,{r1-r4,r14}
  696. mov      r10,r0
  697. cmp      r0,#0
  698.  blne     canonicalise      \
  699. 6ldmvsfd  r13!,{r1-r4,pc}   \ catch any errors here
  700. Cmov      r4,r0             \ r4 -> canonicalised name to remove
  701. Fswi      
  702. my_swi("StackInfo")      \ get head, tail, entries, size
  703. +mov      r3,r0             \ r3 -> head
  704. 3mov      r1,r4             \ r1 -> name to find
  705. -cmp      r2,#0             \ stack empty?
  706. 6bne      uds_find_entry    \ if not, find and kill
  707. mov      r0,r4
  708. cmp      r0,#0
  709. ,blne     freeblock         \ free buffer
  710. +mov      r0,r10            \ restore r0
  711. 0ldmfd    r13!,{r1-r4,pc}^  \ exit (no error)
  712. .uds_find_entry
  713. mov      r1,r4
  714. 0cmp      r1,#0             \ remove top dir?
  715. 4beq      found_match       \ don't do the search
  716. .uds_search
  717. 6ldr      r0,[r3,#stackentry_name%]  \ get name ptr
  718. @bl       lowcmp                     \ same as search string?
  719. 2cmp      r0,#0                      \ matched?
  720. )beq      found_match                \
  721. &ldr      r3,[r3,#stackentry_prev%]
  722. cmp      r3,#0
  723. bne      uds_search
  724. mov      r0,r1
  725. bl       freeblock
  726. mov      r0,r10
  727. ;ldmfd    r13!,{r1-r4,pc}^  \ not an error if not found!
  728. .found_match
  729. mov      r0,r1
  730. cmp      r0,#0
  731. blne     freeblock
  732. 9ldr      r0,[r3,#stackentry_prev%]  \ r0 = this->prev
  733. 9ldr      r2,[r3,#stackentry_next%]  \ r2 = this->next
  734. Gstmfd    r13!,{r0,r2}               \ stack this->prev & this->next
  735. 9cmp      r0,#0                      \ if (this->prev)
  736. Jstrne    r2,[r0,#stackentry_next%]  \    this->prev->next = this->next
  737. 9cmp      r2,#0                      \ if (this->next)
  738. Jstrne    r0,[r2,#stackentry_prev%]  \    this->next->prev = this->prev
  739. &ldr      r0,[r3,#stackentry_name%]
  740. bl       freeblock
  741. mov      r0,r3
  742. bl       freeblock
  743. ldr      r12,[r12]
  744. %ldr      r0,[r12,#dirstack_head%]
  745. %ldr      r1,[r12,#dirstack_tail%]
  746. Jldmfd    r13!,{r2,r4}               \ r2 = this->prev, r4 = this->next
  747. 8cmp      r0,r3                      \ if head = this
  748. >streq    r2,[r12,#dirstack_head%]   \    head = this->prev
  749. 8cmp      r1,r3                      \ if tail = this
  750. >streq    r4,[r12,#dirstack_tail%]   \    tail = this->next
  751. mov      r0,r10
  752. ;ldmfd    r13!,{r1-r4,pc}^  \ not an error if not found!
  753. .tolower
  754. \ On entry, r3 = character
  755. (\ On exit, r3 = lowercase equivalent
  756. cmp      r3,#31
  757. movle    r3,#0
  758. cmp      r3,#
  759. movlts   pc,r14
  760. cmp      r3,#
  761. addle    r3,r3,#32
  762. movs     pc,r14
  763. .lowcmp
  764. \ On entry:
  765. \        r0 ->string 1
  766. \        r1 ->string 2
  767. \ On exit:
  768. F\        r0 = character at which strings differ, or 0 if identical
  769. stmfd    r13!,{r2-r4,r14}
  770. mov      r2,#0
  771. .lowcmp_loop
  772. ldrb     r3,[r0,r2]
  773. bl       tolower
  774. mov      r4,r3
  775. ldrb     r3,[r1,r2]
  776. bl       tolower
  777. add      r2,r2,#1
  778. cmp      r4,#0
  779. ble      lowcmp_fs
  780. cmp      r4,r3
  781. beq      lowcmp_loop
  782. mov      r0,r2
  783. ldmfd    r13!,{r2-r4,pc}^
  784. .lowcmp_fs
  785. mov      r0,#0
  786. ldmfd    r13!,{r2-r4,pc}^
  787. .read_pwd_swi
  788. stmfd  r13!,{r14}
  789. ldr    r0,[r12]
  790. 7Jadd    r0,r0,#scratch_offset%         \ v1.20; SKIP OVER OUR WORKSPACE
  791. bl     read_pwd
  792. ldmfd  r13!,{pc}^
  793. stmfd  r13!,{r0-r1,r14}
  794. =.ldr    r0,[r12]          \ get ->workspace
  795. >Jadd    r0,r0,#scratch_offset%         \ v1.20; skip over our workspace
  796. ?'bl     read_pwd          \ read CSD
  797. @+swi    "XOS_Write0"      \ write string
  798. A!swi    "XOS_NewLine"     \ LF
  799. B#ldmfd  r13!,{r0-r1,pc}^  \ exit
  800. .read_pwd
  801. stmfd  r13!,{r2-r5,r14}
  802. F!mov    r2,r0         \ buffer
  803. mov    r0,#37        \
  804. adr  (1,pathname)   \ pathname
  805. mov    r3,#0
  806. mov    r4,#0
  807. KKmov    r5,#bufsize%        \ buffer size can now be changed more easily
  808. LGsub    r5,r5,#scratch_offset% \ scratch_offset% bytes not available
  809. swi    "XOS_FSControl"
  810. bvs    fsc_error
  811. cmp    r5,#0
  812. ble    buffertoosmall
  813. QOadd    r5,r5,#scratch_offset%\ fudge the bytes free value to account for WS
  814. R(rsb    r5,r5,#bufsize%  \ var length
  815. S    .exit
  816. T%mov    r1,r5         \ var length
  817. U!mov    r0,r2         \ buffer
  818. ldmfd  r13!,{r2-r5,pc}^
  819. .buffertoosmall
  820. adr  (0,btsmlm)
  821. .fsc_error
  822. add    r0,r0,#4
  823. mov    r1,#0
  824. .copyerror
  825. ldrb   r3,[r0,r1]
  826. strb   r3,[r2,r1]
  827. add    r1,r1,#1
  828. cmp    r3,#31
  829. bgt    copyerror
  830. b)subs   r5,r1,#1       \ string length
  831. b      exit
  832. .setvariable
  833. stmfd  r13!,{r0-r4,r14}
  834. adr  (0,variablename)
  835. adr  (1,variablecode)
  836. i/mov    r2,#(endofvariablecode-variablecode)
  837. mov    r3,#0
  838. mov    r4,#16
  839. swi    "XOS_SetVarVal"
  840. ldmvsfd   r13!,{r0-r4,pc}
  841. adr  (0,variable2_name)
  842. adr  (1,variable2_code)
  843. p2mov    r2,#(end_variable2_code-variable2_code)
  844. mov    r3,#0
  845. mov    r4,#16
  846. swi    "XOS_SetVarVal"
  847. ldmfd  r13!,{r0-r4,pc}
  848. .unsetvariable
  849. stmfd  r13!,{r0-r4,r14}
  850. adr  (0,variablename)
  851. adr  (1,variablecode)
  852. mvn    r2,#1
  853. mov    r3,#0
  854. mov    r4,#16
  855. swi    "XOS_SetVarVal"
  856. adr  (0,variable2_name)
  857. adr  (1,variable2_code)
  858. mvn    r2,#1
  859. mov    r3,#0
  860. mov    r4,#16
  861. swi    "XOS_SetVarVal"
  862. ldmfd  r13!,{r0-r4,pc}
  863. ..setvariablevalue_ini           \ Mung Ho!
  864. \ On entry:
  865. !\        r1 -> (string) value
  866. +\        r2 = length of value (ignored)
  867. \        r12 = workspace
  868. stmfd    r13!,{r0,r14}
  869. Pmov      r0,#1<<31         \ must terminate with ctrl or space, default base
  870. 2swi      "XOS_ReadUnsigned"\ convert to number
  871. &ldmvsfd  r13!,{r1,pc}      \ oops?
  872. 7mov      r0,r2             \ value (r1->terminator)
  873. 3mov      r4,r1             \ r4 = -> terminator
  874. E\swi      
  875. my_swi("MaxLen")\ can't use our own SWIs in init code!
  876. $add      r1,r12,#elipsis_offset%
  877. (str      r0,[r12,#csdvarlen_offset%]
  878. <b        process_elips_arg  \ as normal set variable now
  879. .variable2_code
  880. 5movs      pc,r14              \ write entry point
  881. 4stmfd     r13!,{r14}          \ read entry point
  882. +swi       
  883. my_swi("Read")    \ read PWD
  884. 5mov       r2,r1               \ length (excl. \0)
  885. )ldmfd     r13!,{pc}^          \ byee!
  886. .end_variable2_code
  887. .variablecode
  888. 2b      setmaxlength        \ write entry point
  889. 1stmfd  r13!,{r14}          \ read entry point
  890. ,swi    
  891. my_swi("Read")    \ read the PWD
  892. Hmov    r1,#0               \ default length (ie. get from workspace)
  893. Imov    r2,#0               \ default elipsis (ie. get from workspace)
  894. 3swi    
  895. my_swi("Clip")    \ and clip its length
  896. 8sub    r2,r1,#1            \ length excl. terminator
  897. ldmfd  r13!,{pc}^
  898. ?.setmaxlength              \ write entry point for variable
  899. \ On entry:
  900. !\        r1 -> (string) value
  901. +\        r2 = length of value (ignored)
  902. 4\ On exit, r1,r2,r4,r10,r11,r12 may be corrupted
  903. stmfd    r13!,{r0,r14}
  904. Pmov      r0,#1<<31         \ must terminate with ctrl or space, default base
  905. 2swi      "XOS_ReadUnsigned"\ convert to number
  906. &ldmvsfd  r13!,{r1,pc}      \ oops?
  907. 7mov      r0,r2             \ value (r1->terminator)
  908. 3mov      r4,r1             \ r4 = -> terminator
  909. Amov      r1,#0             \ => leave elipsis alone (for now)
  910. Nswi      
  911. my_swi("MaxLen")\ set length and get the elipsis pointer (in r1)
  912. &ldmvsfd  r13!,{r1,pc}      \ oops?
  913. .process_elips_arg
  914. @\ Right, r1-> old elipsis, r4->next char in var value string
  915. +\ (original) r0 and LR are on the stack
  916. ,.smlcv_skip_spc            \ skip spaces
  917. .ldrb     r0,[r4],#1        \ get next char
  918. /cmp      r0,#32            \ is it a space?
  919. /beq      smlcv_skip_spc    \ if so, hunt on
  920. Fldmltfd  r13!,{r0,pc}^     \ if ctrl, then don't alter the elipsis
  921. L\ Okay, so r4->first real character of elipsis, and r0 is that character
  922. stmfd    r13!,{r0,r1,r4}
  923. Qmov      r14,#1            \ Kids! Don't muck with the link register at home!
  924. 8.parse_or_store            \ r14 = 'parse only' flag
  925. 9cmp      r0,#34            \ is char a '"' character?
  926. =moveq    r10,#0            \ clear 'disallow spaces' flag
  927. ,movne    r10,#1            \ else set it
  928. <subne    r4,r4,#1          \ ... move back onto the char
  929. Acmp      r0,#
  930. "\"        \ was char a '\' (ie. literal quote)
  931. @moveq    r11,#1            \ ... if so, set the 'quote' flag
  932. Qaddeq    r4,r4,#1          \ ... and undo that move back onto char [Mung Ho!]
  933. @movne    r11,#0            \ ... else unset the 'quote' flag
  934. >mov      r12,#max_elipsis_len%  \ max length of an elipsis
  935. .smlcv_cpy_elipsis
  936. .ldrb     r0,[r4],#1        \ get next char
  937. >cmp      r14,#0            \ are we doing it for real yet?
  938. Bstreqb   r0,[r1],#1        \ if so, store in elipsis workspace
  939. 6cmp      r0,#31            \ is it the terminator?
  940. 3ble      smlcv_eoe         \ if so, we're done!
  941. Acmp      r11,#1            \ is the literal 'quote' flag set?
  942. 4moveq    r11,#0            \ ... if so, clear it
  943. Tbeq      smlcv_cpy_elipsis \ ... and loop around (ie. store the char regardless)
  944. Ecmp      r0,#
  945. "\"        \ is this char the literal 'quote' char?
  946. Dmoveq    r11,#1            \ ...if so, then set the 'quote' flag
  947. Bsubeq    r1,r1,#1          \ ... back up onto the (stored) '\'
  948. 4beq      smlcv_cpy_elipsis \ ... and loop around
  949. /cmp      r0,#32            \ is it a space?
  950. 7cmpeq    r10,#1            \ and are spaces banned?
  951. ?beq      smlcv_eoe         \ if so, treat as the terminator
  952. /cmp      r0,#34            \ is it a quote?
  953. Lcmpeq    r10,#0            \ and are spaces allowed (ie. quotes aren't)?
  954. ?beq      smlcv_eoe         \ if so, treat as the terminator
  955. :subs     r12,r12,#1        \ decrement remaining space
  956. >bgt      smlcv_cpy_elipsis \ if spaceleft then loop around
  957. .smlcv_eoe
  958. :cmp      r14,#0            \ are we doing it for real?
  959. moveq    r11,#0
  960. Sstreqb   r11,[r1,#-1]      \ if so overwrite last char (prob. term) with a null
  961. )ldmeqfd  r13!,{r0,pc}^     \ and bye!
  962. 9cmp      r12,#0            \ did we run out of space?
  963. ble      elipsis_too_long
  964. Mcmp      r10,#0            \ I just Lurve ARM assembler! This is so cool!
  965. Dcmpeq    r0,#34            \ See the 'neatCmps!' drawfile for an
  966. ?cmpne    r10,#1            \ explanation of why these work!
  967. Ecmpeq    r11,#0            \ (at the end, eq=>valid, ne=>invalid)
  968.  bne      parse_error       \
  969. 6cmp      r14,#1            \ were we just parsing?
  970. 8ldmnefd  r13!,{r0,pc}^     \ if not, we're finished!
  971. =ldmfd    r13!,{r0,r1,r4}   \ if so, restore old registers
  972. :mov      r14,#0            \ unset the parse only flag
  973. =b        parse_or_store    \ and do it for real this time
  974. .elipsis_too_long
  975. Icmp      r14,#1            \ call me paranoid, but I'm gonna check it
  976. Gldmeqfd  r13!,{r0,r1,r4}   \ if just parsing then unstack registers
  977. adr    (0,eliptl_err)    \ ->error block
  978. +ldmfd    r13!,{r1,r14}     \ get old LR
  979. 4orrs     pc,r14,#1<<28     \ and exit with V set
  980. %.parse_error               \ oops
  981. Icmp      r14,#1            \ call me paranoid, but I'm gonna check it
  982. Gldmeqfd  r13!,{r0,r1,r4}   \ if just parsing then unstack registers
  983.     Qcmp      r11,#1            \ did we barf because of an incomplete \ sequence?
  984. adrc   ("eq",0,incompipe_err)  \ ->error block
  985. adrc   ("ne",0,missingq_err)
  986. +ldmfd    r13!,{r1,r14}     \ get old LR
  987. 4orrs     pc,r14,#1<<28     \ and exit with V set
  988. .endofvariablecode
  989. .finalise
  990. stmfd   r13!,{r14}
  991. bl      unsetvariable
  992. cmp     r10,#1
  993. 5ldmnefd   r13!,{pc}^    \ closedown (for the mo).
  994. Ibl      unstack_all_swi \ only clear the dir. stack on a fatal death!
  995. 0mov     r0,#7           \ free the workspace
  996. )ldr     r2,[r12]        \ ->workspace
  997. $swi     "XOS_Module"    \ do it.
  998. Bldmfd   r13!,{pc}^      \ don't allow errors to stop us dying!
  999. .clip_length_swi
  1000. \ On entry:
  1001. \        r0->string
  1002. !K\        r1=length to clip to (excl. terminator) <=0 means use module's
  1003. "5\        r2=elipsis string <=0 means use module's
  1004. \ On exit:
  1005. $'\        r0->string (ie. preserved)
  1006. %7\        r1=new length of string (incl. terminator)
  1007. stmfd    r13!,{r2-r4,r14}
  1008. '0ldr      r12,[r12]         \ get ->workspace
  1009. (Acmp      r1,#0             \ is the length actually specified
  1010. )Mldrle    r1,[r12,#csdvarlen_offset%] \ if not, get default from workspace
  1011. *@cmp      r2,#0             \ is the elipsis string specified
  1012. +Oaddle    r2,r12,#elipsis_offset%  \ if not, use our string in the workspace
  1013. ,0mov      r3,r1             \ r3 = max length
  1014. -5mov      r4,r2             \ r4 -> elipsis string
  1015. .-mov      r2,r0             \ r2 -> string
  1016. .cls_strlen
  1017. 0)ldrb     r1,[r2],#1        \ get char
  1018. 15cmp      r1,#31            \ is it the terminator
  1019. 25bgt      cls_strlen        \ if not, keep looking
  1020. 3Fsub      r1,r2,r0          \ r1 = string length (incl. terminator)
  1021. 4Acmp      r1,r3             \ check to see if in range already
  1022. 5Dldmlefd  r13!,{r2-r4,pc}^  \ if it is, we can exit straight away
  1023. mov      r10,#0
  1024. 7B.clse_strlen               \ find length of the elipsis string
  1025. 8)ldrb     r11,[r4,r10]      \ get char
  1026. 95cmp      r11,#31           \ is it the terminator
  1027. :0addgt    r10,r10,#1        \ if not, move on
  1028. ;7bgt      clse_strlen       \ and on (length in r10)
  1029. <Ccmp      r10,r3            \ is elipsis longer than max length?
  1030. =:movgt    r10,r3            \ if so, clip to max length
  1031. >Qsub      r3,r3,r10         \ don't forget to allow for the elipsis! (r10=len)
  1032. ?Cmov      r2,r3,lsr#1       \ r2 = number of lefthand characters
  1033. @Aadd      r1,r0,r2          \ r1 -> first character to replace
  1034. ACsub      r3,r3,r2          \ r3 = number of righthand charaters
  1035. B=sub      r2,r1,#1          \ r2 -> character we're at - 1
  1036. .cpy_elipsis
  1037. D6subs     r10,r10,#1        \ while ( (--elen)>=0 )
  1038. E ldrgeb   r11,[r4],#1       \
  1039. F strgeb   r11,[r2,#1]!      \
  1040. G bge      cpy_elipsis       \
  1041. HHadd      r1,r2,#1          \ r1-> byte after last char of terminator
  1042. .find_term
  1043. J.ldrb     r12,[r2,#1]!      \ get next char
  1044. K5cmp      r12,#31           \ is it the terminator
  1045. L0bgt      find_term         \ if not, hunt on
  1046. M%\ Okay, so now r2->the terminator
  1047. NCsub      r2,r2,r3          \ r2 -> first char of righthand side
  1048. .copy_right
  1049. P)ldrb     r12,[r2],#1       \ get char
  1050. Q&strb     r12,[r1],#1       \ store
  1051. R6cmp      r12,#31           \ is it the terminator?
  1052. bgt      copy_right
  1053. T>sub      r1,r1,r0          \ new length (incl. terminator)
  1054. U%ldmfd    r13!,{r2-r4,pc}^  \ exit
  1055. .set_max_len_swi
  1056. Y;\ On entry, r0 = new max length, r1->new elipsis string
  1057. Z(\ (<=0 implies read but don't alter)
  1058. [G\ On exit,  r0 = max length in effect, r1->elipsis string in effect
  1059. \6ldr      r12,[r12]         \ get workspace pointer
  1060. ]5cmp      r0,#0             \ is length specified?
  1061. ^Gldrle    r0,[r12,#csdvarlen_offset%] \ if not, then use the current
  1062. _:strgt    r0,[r12,#csdvarlen_offset%] \store new length
  1063. `<cmp      r1,#0             \ is there an elipsis string?
  1064. aFaddle    r1,r12,#elipsis_offset%     \ if not, get current elipsis
  1065. b+movles   pc,r14            \ and return
  1066. c%add      r12,r12,#elipsis_offset%
  1067. d5mov      r0,r12            \ elipsis base pointer
  1068. eKadd      r11,r12,#max_elipsis_len%  \ elipsis must be 'n' chars or less
  1069. fH.sml_cpy_elipsis           \ copy the new elipsis into the workspace
  1070. g)ldrb     r10,[r1],#1       \ get char
  1071. h5cmp      r0,r11            \ is elipsis too long?
  1072. iFmovge    r10,#0            \ force termination if elipsis too long
  1073. j)strb     r10,[r0],#1       \ store it
  1074. k,cmp      r10,#31           \ terminator?
  1075. l%bgt      sml_cpy_elipsis   \ loop
  1076. m.mov      r1,r12            \ ->new elipsis
  1077. nRldr      r0,[r12,#csdvarlen_offset%-elipsis_offset%]     \ get current max len
  1078. o%movs     pc,r14            \ bye!
  1079. r4.pushdir_cmd               \ wrapper for the swi
  1080. s stmfd    r13!,{r1,r14}     \
  1081. t>ldrb     r1,[r0]          \ get first char of command tail
  1082. u%cmp      r1,#31           \ ctrl?
  1083. vAmovle    r0,#0            \ replace with NULL (ie. implies @)
  1084. swi      
  1085. my_swi("PushDir")
  1086. x8ldmfd    r13!,{r1,pc}      \ exit (with any errors!)
  1087. .unpushdir_cmd
  1088. { stmfd    r13!,{r1,r14}     \
  1089. |>ldrb     r1,[r0]          \ get first char of command tail
  1090. }%cmp      r1,#31           \ ctrl?
  1091. ~Mmovle    r0,#0            \ replace with NULL (ie. implies top directory)
  1092. "swi      
  1093. my_swi("UnstackDir")
  1094. 8ldmfd    r13!,{r1,pc}      \ exit (with any errors!)
  1095. ;.liststack_cmd             \ display the stack contents
  1096. 0stmfd    r13!,{r0-r4,r14}  \ stack some regs
  1097. adr    (0,liststackhead) \ header message
  1098. mov      r1,#0
  1099. mov      r2,#0
  1100. (swi      "XOS_PrettyPrint" \ display
  1101. 3swi      
  1102. my_swi("StackInfo") \ get head & tail
  1103. .pstack_loop
  1104. *cmp      r1,#0             \ done yet?
  1105. beq      pstack_done
  1106. :ldr      r0,[r1,#stackentry_name%]  \ get name pointer
  1107. .swi      "XOS_Write0"      \ print message
  1108. #swi      "XOS_NewLine"     \ NL
  1109. 1ldr      r1,[r1,#stackentry_next%] \ get next
  1110. b        pstack_loop
  1111. .pstack_done
  1112. adr    (0,scnts)
  1113. mov      r4,r2
  1114. mov      r1,#0
  1115. mov      r2,#0
  1116. swi      "XOS_PrettyPrint"
  1117. ldr      r12,[r12]
  1118. $add      r1,r12,#scratch_offset%
  1119. mov      r0,r4
  1120. +mov      r2,#(bufsize%-scratch_offset%)
  1121. #swi      "XOS_ConvertCardinal2"
  1122. swi      "XOS_Write0"
  1123. adr    (0,entries)
  1124. mov      r1,#0
  1125. mov      r2,#0
  1126. swi      "XOS_PrettyPrint"
  1127. $add      r1,r12,#scratch_offset%
  1128. mov      r0,r3
  1129. +mov      r2,#(bufsize%-scratch_offset%)
  1130. #swi      "XOS_ConvertCardinal4"
  1131. swi      "XOS_Write0"
  1132. adr    (0,bytesmess)
  1133. mov      r1,#0
  1134. mov      r2,#0
  1135. swi      "XOS_PrettyPrint"
  1136. ldmfd    r13!,{r0-r4,pc}^
  1137. .swi_make_argv
  1138. %\ On entry, r0  = -> command line
  1139. \           r13 = stack
  1140. \ On exit,  r0 = argc
  1141. \           r1 = argv
  1142. R\           $(argv!0), $(argv!4), ... = argument vector (claimed from the RMA)
  1143. +\           (or V set, r0->error block)
  1144. stmfd    r13!,{r2-r5,r14}
  1145. %mov      r4,#0             \ argc
  1146. 5sub      r1,r0,#1          \ r1->(command line-1)
  1147. (.uia_1 \ find start of next argument
  1148. ldrb     r2,[r1,#1]!
  1149. cmp      r2,#32
  1150. 4beq      uia_1             \ skip leading spaces
  1151. ;blt      uia_3             \ if ctrl, we're out of args
  1152. 'add      r4,r4,#1          \ argc++
  1153. .uia_2 \ found an argument
  1154. ldrb     r2,[r1,#1]!
  1155. cmp      r2,#32
  1156. 5bgt      uia_2             \ find next ctrl/space
  1157. Dbeq      uia_1             \ if space, look for another argument
  1158. .uia_3 \ found terminator
  1159. 7sub      r5,r1,r0          \ length of command line
  1160. 1add      r5,r5,#2          \ +2 for paranoia!
  1161. 4mov      r1,r0             \ r1 = ->command line
  1162. Imov      r3,r4,lsl#2       \ r3 = argc*4 (ie. #bytes needed for argv)
  1163. &mov      r0,#6             \ claim
  1164. 5swi      "XOS_Module"      \ claim space for argv
  1165. Kldmvsfd  r13!,{r2-r5,pc}   \ if error, restore regs from stack and exit
  1166. 5stmfd    r13!,{r2}         \ push argv onto stack
  1167. *mov      r0,#6             \ paranoia!
  1168. 7mov      r3,r5             \ length of command line
  1169. Bswi      "XOS_Module"      \ claim space for command line copy
  1170. Pbvc      uia_4             \ if there's an error, the cleanup is a bit messy
  1171. 4ldmfd    r13!,{r2}         \ get argv from stack
  1172. 3mov      r4,r0             \ preserve error ptr
  1173. %mov      r0,#7             \ free
  1174. *swi      "XOS_Module"      \ free argv
  1175. 2mov      r0,r4             \ restore error ptr
  1176. -ldmfd    r13!,{r2-r5,r14}  \ restore regs
  1177. 4orrs     pc,r14,#1<<28     \ and exit with V set
  1178. R.uia_4 \ set up argv (argv[0] in r2, argv on stack, r1->command line, r4=argc)
  1179. *ldmfd    r13!,{r3}         \ r3 = argv
  1180. >stmfd    r13!,{r3,r4}      \ push argv and argc onto stack
  1181. *.uia_5 \ next argument of command line
  1182. .str      r2,[r3],#4        \ store argv[i]
  1183. !.uia_6 \ find end of argument
  1184. ;ldrb     r5,[r1],#1        \ get char from command line
  1185. -cmp      r5,#32            \ is it a ctrl
  1186. 1strgtb   r5,[r2],#1        \ store in argv[0]
  1187. >bgt      uia_6             \ find next non-space, non-ctrl
  1188. 'subs     r4,r4,#1          \ argc--
  1189. Bbeq      uia_8             \ if argc==0 then out of arguments!
  1190. .uia_7 \ skip spaces
  1191. >ldrb     r5,[r1],#1        \ get next char of command line
  1192. /cmp      r5,#32            \ is it a space?
  1193. 4beq      uia_7             \ find next non-space
  1194. mov      r5,#0
  1195. >strb     r5,[r2],#1        \ replace the space with a NULL
  1196. /subgt    r1,r1,#1          \ back up a char
  1197. Fbgt      uia_5             \ if it's not a ctrl, loop around again
  1198. T.uia_adny_f_u              \ if it *is* a control, then Adny's fucked up (again)
  1199. debug("Adny fucked up
  1200. Eldmfd    r13!,{r3,r4}      \ pop argv into r3 (also argc into r4)
  1201. Hldr      r2,[r3]           \ get argv[0] (ie. the command line copy)
  1202. %mov      r0,#7             \ free
  1203. -swi      "XOS_Module"      \ free argv[0]
  1204. mov      r2,r3
  1205. mov      r0,#7
  1206. *swi      "XOS_Module"      \ free argv
  1207. adr    (0,adnyfu)        \ ->error block
  1208. -ldmfd    r13!,{r2-r5,r14}  \ restore regs
  1209. 4orrs     pc,r14,#1<<28     \ and exit with V set
  1210. .uia_8 \ out of arguments
  1211. mov      r0,#0
  1212. 8strb     r0,[r2]           \ terminate last argument
  1213. 2ldmfd    r13!,{r1,r2}      \ pop argv ard argc
  1214. 2mov      r0,r2             \ return argc in r0
  1215. )ldmfd    r13!,{r2-r5,pc}^  \ and exit
  1216. .swi_free_argv
  1217. I\ On entry, r1=argv, on exit all regs preserved (or r0->err if V set)
  1218.  mov      r10,r0            \
  1219. 3mov      r11,r2            \ preserve some regs
  1220. !mov      r12,r14           \ 
  1221. (ldr      r2,[r1]           \ argv[0]
  1222. )mov      r0,#7             \ 7 = free
  1223.  swi      "XOS_Module"      \
  1224. Hmovvc    r2,r1             \ argv (no point if previous free failed)
  1225. Dswivc    "XOS_Module"      \ only try if the free argv[0] worked
  1226.     =movvc    r0,r10            \ only restore r0 if no errors
  1227. 6mov      r2,r11            \ but always restore r2
  1228. Fmov      pc,r12            \ NB! not movS - want to return errors!
  1229. .addtopath_cmd
  1230. mov      r2,#0
  1231. b        adpath_common
  1232. .prependpath_cmd
  1233. mov      r2,#1
  1234. .adpath_common
  1235. stmfd    r13!,{r14}
  1236.  swi      
  1237. my_swi("MakeArgV")
  1238. ldmvsfd  r13!,{pc}
  1239. \ r0 = argc, r1 = argv
  1240. ,sub      r4,r0,#1          \ r4 = argc-1
  1241. *mov      r5,r1             \ r5 = argv
  1242. 4ldr      r0,[r1],#4        \ get argv[0], argv++
  1243. .process_args
  1244. add      r6,r1,#4
  1245. ldr      r1,[r1]
  1246. debpp  ("Adding directory ",1)
  1247. debpp  ("to path ",0)
  1248. "!swi      
  1249. my_swi("AddToPath")
  1250. bvs      atpc_failure
  1251. mov      r1,r6
  1252. subs     r4,r4,#1
  1253. bgt      process_args
  1254. mov      r1,r5
  1255. ( swi      
  1256. my_swi("FreeArgV")
  1257. blvs     ie_nf
  1258. ldmfd    r13!,{pc}^
  1259. .atpc_failure
  1260. mov      r1,r5
  1261. mov      r5,r0
  1262. . swi      
  1263. my_swi("FreeArgV")
  1264. blvs     ie_nf
  1265. mov      r0,r5
  1266. ldmfd    r13!,{r14}
  1267. orrs     pc,r14,#1<<28
  1268. .commtable
  1269. 9#equs "pwd":dcb 0:align:equd pwd
  1270. :)     equd &00000:equd 0:equd  pwdhelp
  1271. <-equs "PushDir":dcb 0:align \ command name
  1272. =/equd pushdir_cmd           \ offset to code
  1273. >*equb &00                   \ min parms
  1274. ?>equb &00                   \ GSTrans map for first 8 parms
  1275. @*equb &01                   \ max parms
  1276. A&equb &00                   \ flags
  1277. BAequd pushdir_syntax        \ offset to invalid syntax message
  1278. C7equd pushdir_help          \ offset to help message
  1279. E-equs "PopDir":dcb 0:align  \ command name
  1280. F/equd popdir_swi            \ offset to code
  1281. G*equb &00                   \ min parms
  1282. H>equb &00                   \ GSTrans map for first 8 parms
  1283. I*equb &00                   \ max parms
  1284. J&equb &00                   \ flags
  1285. KAequd popdir_syntax         \ offset to invalid syntax message
  1286. L7equd popdir_help           \ offset to help message
  1287. N0equs "UnPushDir":dcb 0:align  \ command name
  1288. O/equd unpushdir_cmd         \ offset to code
  1289. P*equb &00                   \ min parms
  1290. Q>equb &00                   \ GSTrans map for first 8 parms
  1291. R*equb &01                   \ max parms
  1292. S&equb &00                   \ flags
  1293. TAequd unpushdir_syntax      \ offset to invalid syntax message
  1294. U7equd unpushdir_help        \ offset to help message
  1295. W0equs "ListStack":dcb 0:align  \ command name
  1296. X/equd liststack_cmd         \ offset to code
  1297. Y*equb &00                   \ min parms
  1298. Z>equb &00                   \ GSTrans map for first 8 parms
  1299. [*equb &00                   \ max parms
  1300. \&equb &00                   \ flags
  1301. ]Aequd liststack_syntax      \ offset to invalid syntax message
  1302. ^7equd liststack_help        \ offset to help message
  1303. `0equs "KillStack":dcb 0:align  \ command name
  1304. a1equd unstack_all_swi         \ offset to code
  1305. b*equb &00                   \ min parms
  1306. c>equb &00                   \ GSTrans map for first 8 parms
  1307. d*equb &00                   \ max parms
  1308. e&equb &00                   \ flags
  1309. fBequd unstackall_syntax      \ offset to invalid syntax message
  1310. g8equd unstackall_help        \ offset to help message
  1311. i equs "AddToPath":dcb 0:align
  1312. j0equd addtopath_cmd          \ offset to code
  1313. k-equb &02                      \ min parms
  1314. lAequb &00                      \ GSTrans map for first 8 parms
  1315. m-equb &ff                      \ max parms
  1316. n)equb &00                      \ flags
  1317. oCequd addtopath_syntax        \ offset to invalid syntax message
  1318. p9equd addtopath_help          \ offset to help message
  1319. r$equs "PrependToPath":dcb 0:align
  1320. s2equd prependpath_cmd          \ offset to code
  1321. t-equb &02                      \ min parms
  1322. uAequb &00                      \ GSTrans map for first 8 parms
  1323. v-equb &ff                      \ max parms
  1324. w)equb &00                      \ flags
  1325. xEequd prependpath_syntax        \ offset to invalid syntax message
  1326. y;equd prependpath_help          \ offset to help message
  1327. \ Help only entries
  1328. }%equs "CSD$Var":dcb 0:align:equd 0
  1329. ~,     equd &00000:equd 0:equd  csdvarhelp
  1330. %equs "PWD$Var":dcb 0:align:equd 0
  1331. ,     equd &00000:equd 0:equd  pwdvarhelp
  1332. ,equs "DirectoryStack":dcb 0:align:equd 0
  1333. /     equd &00000:equd 0:equd  dirstack_help
  1334. equd 0
  1335. 1.ie_nf            \ internal error, non fatal
  1336. stmfd    r13!,{r1-r4,r14}
  1337. mov      r3,r0
  1338. mov      r4,r14
  1339. adr    (0,ienfmh)
  1340. mov      r1,#0
  1341. mov      r2,#0
  1342. swi      "XOS_PrettyPrint"
  1343. mov      r0,r4
  1344. orr      r0,r0,#1<<28
  1345. swi      
  1346. my_swi("Debug1")
  1347. add      r0,r3,#4
  1348. swi      "XOS_PrettyPrint"
  1349. adr    (0,ienfmt)
  1350. swi      "XOS_PrettyPrint"
  1351. mov      r0,r3
  1352. ldmfd    r13!,{r1-r4,pc}^
  1353. .print_address
  1354. \ On entry, r0 = address
  1355. !\ On exit, all regs preserved
  1356. stmfd    r13!,{r0-r2,r14}
  1357. mov      r10,r0
  1358. ldr      r12,[r12]
  1359. add      r12,r12,#bufsize%
  1360. sub      r12,r12,#16
  1361. bl       printmode
  1362. swi      256+
  1363. mov      r1,#%11
  1364. !orr      r1,r1,#(%111111)<<26
  1365. bic      r0,r0,r1
  1366. mov      r1,r12
  1367. mov      r2,#16
  1368. swi      "XOS_ConvertHex8"
  1369. swivc    256+
  1370. swivc    "XOS_Write0"
  1371. swi      256+
  1372. mov      r0,r10
  1373. bl       printflags
  1374. swi      256+32
  1375. ldmfd    r13!,{r0-r2,pc}^
  1376. .printmode
  1377. stmfd    r13!,{r0,r1,r14}
  1378. and      r1,r0,#%11
  1379. adr      r0,modes_base
  1380. ;add      r0,r0,r1,lsl#2    \ offset into table of words
  1381. (swi      "XOS_Write0"      \ display
  1382. ldmfd    r13!,{r0,r1,pc}^
  1383. .modes_base
  1384. .\ user mode       = %00 :  dcb "USR":dcb 0
  1385. .\ fast interrupt  = %01 :  dcb "FIQ":dcb 0
  1386. .\ interrupt mode  = %10 :  dcb "IRQ":dcb 0
  1387. .\ supervisor mode = %11 :  dcb "SVC":dcb 0
  1388. .flags_base
  1389. 1\ Flags are:               dcb "nzcvif":dcb 0
  1390.     align
  1391. .printflags
  1392. stmfd    r13!,{r0-r2,r14}
  1393. !and      r1,r0,#(%111111)<<26
  1394. adr      r2,flags_base
  1395. .pfloop
  1396. 0ldrb     r0,[r2],#1        \ get flag letter
  1397. &cmp      r0,#0             \ done?
  1398. ldmeqfd  r13!,{r0-r2,pc}^
  1399. 0tst      r1,#1<<31         \ is top bit set?
  1400. >moveq    r0,#0            \ if not, replace flag with NULL
  1401. 0swi      "XOS_WriteC"      \ print character
  1402. 5mov      r1,r1,lsl#1       \ shift onto next flag
  1403. b        pfloop
  1404. .pwdhelp
  1405. Ddcb 
  1406. osd("Prints the current directory's full path name."):dcb 0
  1407. .csdvarhelp
  1408. Jdcb 
  1409. osd("The CSDVar module provides a magic system variable called ")
  1410. Kdcb 
  1411. osd("'CSD$Var' that holds the pathname of the current directory.")
  1412. dcb 13:dcb 13
  1413. Ndcb 
  1414. osd("Since this pathname can get quite long, the CSDVar module can ")
  1415. Pdcb 
  1416. osd("chop a chunk out of the middle and replace it with an 'elipsis' ")
  1417. Odcb 
  1418. osd("sequence (eg. '...') to make the path a more reasonable length.")
  1419. dcb 13:dcb 13
  1420. Kdcb 
  1421. osd("You can set the (maximum) length and 'elipsis' sequence by ")
  1422. 5dcb 
  1423. osd("*set-ing the CSD$Var system variable:")
  1424. Idcb 13:dcb 9:dcb 
  1425. osd("*Set CSD$Var <max_length> [<elipsis_string>]")
  1426. dcb 13:dcb 13
  1427. Sdcb 
  1428. osd("Specifying a <max_length> of 0 means ""don't alter the max length""")
  1429. Qdcb 
  1430. osd(". If the <elipsis_string> is omitted, then only the <max_length> ")
  1431. Ndcb 
  1432. osd("parameter is considered (the <max_length> parameter *must* be ")
  1433. osd("supplied).")
  1434. dcb 13:dcb 13
  1435. Ldcb 
  1436. osd("To include spaces in the 'elipsis' string, surround it with ")
  1437. 0dcb 
  1438. osd("double-quotation marks, ie. ""s.")
  1439. dcb 13:dcb 13
  1440. Ldcb 
  1441. osd("Prefixing any part of the 'elipsis' string with a backslash ")
  1442. Sdcb 
  1443. osd("character (ie. \) causes the next character to be taken literally, ")
  1444. ,dcb 
  1445. osd("eg. use \"" to include a "".")
  1446. dcb 13:dcb 13
  1447. Mdcb 
  1448. osd("The minimum value of <max_len> is 10, and the maximum is 440.")
  1449. dcb 13:dcb 13
  1450. Sdcb 
  1451. osd("Note that the <max_len> and 'elipsis' string *only* affect CSD$Var,")
  1452. 8dcb 
  1453. osd(" and have no effect on the *pwd command.")
  1454. dcb 13:dcb 13
  1455. osd("Suggested use:")
  1456. <dcb 13:dcb 9:dcb 
  1457. osd("SetMacro CLI$Prompt <CSD$Var> *")
  1458.     dcb 0
  1459. .pwdvarhelp
  1460. Ndcb 
  1461. osd("PWD$Var is similar to CSD$Var except that it is never clipped ")
  1462. Odcb 
  1463. osd("(and no elipsis is inserted).  This can be useful as it allows ")
  1464. :dcb 
  1465. osd("the CSD's full name to be examined."):dcb 13
  1466. Mdcb 
  1467. osd("Eg. *Set This$Dir <PWD$Var>. Obviosuly CSD$Var is unsuitable ")
  1468. %dcb 
  1469. osd("for this sort of use.")
  1470. dcb 0  
  1471. .dirstack_help
  1472. Jdcb 
  1473. osd("The directory stack features of CSDVar extend the concept ")
  1474. Mdcb 
  1475. osd("of the OS *back command (the *Back command swaps between the ")
  1476. ?dcb 
  1477. osd("current (CSD) and previous directories)."):dcb 13
  1478. Odcb 
  1479. osd("CSDVar allows you to 'push' directories onto a stack, and then ")
  1480. Edcb 
  1481. osd("'pop' them off later.  There is no limit on how many ")
  1482. Kdcb 
  1483. osd("directories you can store in this way.  CSDVar also allows ")
  1484. Ldcb 
  1485. osd("you to remove any single directory, or all directories from ")
  1486. :dcb 
  1487. osd("the stack without changing the CSD."):dcb 13
  1488. ;dcb 
  1489. osd("The commands that operate on the stack are:")
  1490.     Rdcb 13:dcb p$+
  1491. osd("*PushDir "+t$+" pushes a directory onto the stack"):dcb 13
  1492. Ndcb p$+
  1493. osd("*PopDir "+t$+" pops the top directory from the stack"):dcb 13
  1494. Ndcb p$+
  1495. osd("*UnStackDir "+t$+" as *PopDir, but leaves the CSD unchanged")
  1496. Rdcb 13:dcb p$+
  1497. osd("*KillStack "+t$+" removes all directories from the stack")
  1498. Kdcb 13:dcb p$+
  1499. osd("*ListStack "+t$+" lists the contents of the stack")
  1500.     dcb 0
  1501. .pushdir_help
  1502. Ndcb 
  1503. osd("The *PushDir command stores the current directory name on the ")
  1504. Kdcb 
  1505. osd("CSDVar stack. You can push as many directories as you like ")
  1506. +dcb 
  1507. osd("(memory permitting)."):dcb 13
  1508. Sdcb 
  1509. osd("To get the directories back off the stack, use *PopDir (qv.)"):dcb 13
  1510. Kdcb 
  1511. osd("To remove directories from the stack, use *UnPushDir"):dcb 13
  1512. Kdcb 
  1513. osd("To list the directories on the stack, use *ListStack"):dcb 13
  1514. .pushdir_syntax
  1515. 5dcb 
  1516. osd("Syntax: *PushDir [<directory>]"):dcb 13
  1517. Qdcb 
  1518. osd("if <directory> is omitted, then the CSD (ie. @) is assumed."):dcb 0
  1519. .popdir_help
  1520. Odcb 
  1521. osd("The *PopDir command retrieves the top entry from the directory ")
  1522. Odcb 
  1523. osd("stack, and sets the CSD to this directory.  The stack entry is ")
  1524. osd("removed."):dcb 13
  1525. .popdir_syntax
  1526. !%dcb 
  1527. osd("Syntax: *PopDir"):dcb 0
  1528. .unpushdir_help
  1529. $Qdcb 
  1530. osd("The *UnPushDir removes specified directory from the stack."):dcb 13
  1531. %Jdcb 
  1532. osd("If the specified directory has been pushed more than once ")
  1533. &Adcb 
  1534. osd("then only the most recent will be removed."):dcb 13
  1535. .unpushdir_syntax
  1536. (4dcb 
  1537. osd("Syntax: *UnPushDir <directory>"):dcb 0
  1538. .liststack_help
  1539. +Jdcb 
  1540. osd("The *ListStack command displays the directory stack, most ")
  1541. ,Odcb 
  1542. osd("recently pushed directory last.  *ListStack also tells you how ")
  1543. -Ldcb 
  1544. osd("many directories are stacked, and how much memory the stack ")
  1545. . dcb 
  1546. osd("occupies."):dcb 13
  1547. .liststack_syntax
  1548. 0(dcb 
  1549. osd("Syntax: *ListStack"):dcb 0
  1550. .unstackall_help
  1551. 3Mdcb 
  1552. osd("The *KillStack command removes every directory from the stack")
  1553. 4=dcb 31:dcb 
  1554. osd("freeing all storage as it goes."):dcb 13
  1555. .unstackall_syntax
  1556. 6(dcb 
  1557. osd("Syntax: *KillStack"):dcb 0
  1558. .addtopath_help
  1559. 9Odcb 
  1560. osd("The *AddToPath command appends directories to a path variable, ")
  1561. :Qdcb 
  1562. osd("but only if they are not already present in the path variable to ")
  1563. ;Ndcb 
  1564. osd("start with.  The entries added to the path variable are *not* ")
  1565. <Ldcb 
  1566. osd("GSTrans'd, or canonicalised in any way (but *AddToPath will ")
  1567. =Odcb 
  1568. osd("take any such translations into account when checking the path ")
  1569. >3dcb 
  1570. osd("variable for the directory)."):dcb 13
  1571. ?Ndcb 
  1572. osd("The new entries are appended to the path variable. To prepend ")
  1573. @@dcb 
  1574. osd("the new entries, use *PrependToPath (qv.)"):dcb 13
  1575. .addtopath_syntax
  1576. BRdcb 
  1577. osd("Syntax: *AddToPath <path variable> <directory> [ <directory> ... ]")
  1578. C    dcb 0
  1579. .prependpath_help
  1580. FQdcb 
  1581. osd("As *AddToPath (qv.) but prepends the new directories to the path ")
  1582. G<dcb 
  1583. osd("variable, rather than appending them."):dcb 13
  1584. .prependpath_syntax
  1585. IQdcb 
  1586. osd("Syntax: *PrependToPath <path variable> <directory> [ <directory> ")
  1587. osd("... ]")
  1588. K    dcb 0
  1589. OD.eliptl_err       equd 1:equs "'Elipsis' string too long":equb 0
  1590. P@.incompipe_err    equd 1:equs "Incomplete \ sequence":equb 0
  1591. Q5.missingq_err     equd 1:equs "Missing """:equb 0
  1592. RG.btsmlm           equd 1:equs "Buffer too small to read CSD":equb 0
  1593. SI.nirma_eblk       equd 1:equs "Head/Tail *must* be in the RMA":equb 0
  1594. TP.stack_what_stack equd 1:equs "Adny has fucked the stack up Real Bad
  1595. ":dcb 0
  1596. UH.adnyfu           equd 1:equs "Adny fucked up the ArgV thangs":dcb 0
  1597. W+.variablename     equs "CSD$Var":equb 0
  1598. X+.variable2_name   equs "PWD$Var":equb 0
  1599. Y+.defelips         equs elipsis$:equb 13
  1600. Z%.pathname         equs "@":equb 0
  1601. [*.stringpath       equs "$path>":equb 0
  1602. \>.scnts            equs 
  1603. osd("Stack contains"):dcb 31:dcb 0
  1604. ]=.entries          dcb 31:equs 
  1605. osd("directories ("):dcb 0
  1606. ^G.liststackhead    dcb 13:equs 
  1607. osd("Directory stack:"):dcb 13:dcb 0
  1608. _C.bytesmess        dcb 31:equs 
  1609. osd("bytes used)."):dcb 13:dcb 0
  1610. `G.ienfmh           dcb 
  1611. osd("CSDVar internal error at"):dcb 31:dcb 0
  1612. aG.ienfmt           dcb 
  1613. osd(", attempting to continue"):dcb 13:dcb 0
  1614. "ok!"
  1615.  SHOWREGS_USED 
  1616.  [OPT pass%:
  1617. showregs:]
  1618. '"Saving module to CSD ... ";
  1619. "OS_File",10,"CSDVar",&FFA,,code%,O%
  1620. "ok!"
  1621. '"Module is ";O%-code%;" bytes (";htos%-htcs%;" bytes saved using OS dict)"
  1622. H3(A%):=
  1623. "000"+
  1624. ~A%,3)
  1625. osd(a$)
  1626. os_dict_tokenise(a$)
  1627.  (pass% 
  1628.  htos%+=
  1629. (a$):htcs%+=
  1630.